﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace SWF.Runtime
{
    public class Sprite : IRenderable, IFrameContainer
    {
        //----------------------------------------------------------------------
        private uint _Id;
        private Rectangle _BoundingBox;

        Vector2 pos = Vector2.Zero;
        Vector2 scale = Vector2.One;

        //----------------------------------------------------------------------
        private Dictionary<uint, KeyValuePair<IContent, PlaceOperation>> _ActiveContentList;

        private Frame[] _TimeLine;
        private uint _CurrentFrame;

        private bool _Playing;

        //----------------------------------------------------------------------
        public uint Id { get { return _Id; } }

        //----------------------------------------------------------------------
        public Sprite(DefineSpriteTag tag)
        {
            _Id = tag.SpriteId;
            _BoundingBox = new Rectangle(tag.ShapeBounds.XMin, tag.ShapeBounds.YMin,
                tag.ShapeBounds.XMax - tag.ShapeBounds.XMin,
                tag.ShapeBounds.YMax - tag.ShapeBounds.YMin);
            _TimeLine = new Frame[tag.FrameCount];
            _ActiveContentList = new Dictionary<uint, KeyValuePair<IContent, PlaceOperation>>();

            _CurrentFrame = 0;
            _TimeLine[_CurrentFrame] = Frame.CreateFrame();
            foreach (IControlTag controlTag in tag.ControlTags)
            {
                _ParseControlTag(controlTag);
            }
            foreach (IPlaceObject placeTag in tag.FirstFrameObjects)
            {
                _ParsePlaceTag(placeTag);
            }
            _CurrentFrame = 0;
            _UpdateFrame();
            _Playing = true;
        }

        //----------------------------------------------------------------------
        public void NextFrame()
        {
            if (!_Playing) return;
            
            if (_CurrentFrame + 2 > _TimeLine.Length)
            {
                _CurrentFrame = 0;
            }
            else
            {
                ++_CurrentFrame;
            }

            _UpdateFrame();

            foreach (KeyValuePair<IContent, PlaceOperation> eContent in _ActiveContentList.Values.Where(element => element.Key is IFrameContainer))
            {
                (eContent.Key as IFrameContainer).NextFrame();
            }
        }

        //----------------------------------------------------------------------
        public void Render(Matrix matrix)
        {
            Matrix m;
            foreach (KeyValuePair<IContent, PlaceOperation> eContent in _ActiveContentList.Values)
            {
                m = matrix;
                m.TranslateX += eContent.Value.PlaceMatrix.TranslateX;
                m.TranslateY += eContent.Value.PlaceMatrix.TranslateY;
                m.ScaleX *= eContent.Value.PlaceMatrix.ScaleX;
                m.ScaleY *= eContent.Value.PlaceMatrix.ScaleY;

                IRenderable ir = eContent.Key as IRenderable;
                if (ir != null)
                {
                    ir.Render(m);
                }
            }
        }

        //----------------------------------------------------------------------
        private void _UpdateFrame()
        {
            if (_CurrentFrame == 0)
            {
                _ActiveContentList.Clear();
            }

            foreach (PlaceOperation placeOp in _TimeLine[_CurrentFrame].PlaceObjectList)
            {
                if (placeOp.Character != 0
                    && !_ActiveContentList.ContainsKey(placeOp.Depth))
                {
                    if (SWFMain.ContentDictionary.ContainsKey(placeOp.Character))
                    {
                        _ActiveContentList.Add(placeOp.Depth, new KeyValuePair<IContent, PlaceOperation>(SWFMain.ContentDictionary[placeOp.Character], placeOp));
                    }
                }

                if (_ActiveContentList.ContainsKey(placeOp.Depth))
                {
                    _ActiveContentList[placeOp.Depth] = new KeyValuePair<IContent, PlaceOperation>(_ActiveContentList[placeOp.Depth].Key, placeOp);
                }
            }
            foreach (RemoveOperation removeOp in _TimeLine[_CurrentFrame].RemoveObjectList)
            {
                if (removeOp.Character != 0)
                {
                    _ActiveContentList.Remove(removeOp.Depth);
                }
                else
                {
                    _ActiveContentList.Remove(removeOp.Depth);
                }
            }

            foreach (List<IAction> actionOpList in _TimeLine[_CurrentFrame].ActionList)
            {
            }
        }
        //----------------------------------------------------------------------
        private void _ParseControlTag(IControlTag tag)
        {
            switch (tag.TagType)
            {
                case TagType.DefineSound:
                    break;
                case TagType.DefineSprite:
                    break;
                case TagType.DoAction:
                    break;
                case TagType.FrameLabel:
                {
                    FrameLabelTag frameLabel = (FrameLabelTag)tag;
                    _TimeLine[_CurrentFrame].Name = frameLabel.TargetName;
                    break;
                }
                case TagType.ShowFrame:
                {
                    if (_CurrentFrame + 2 > _TimeLine.Length)
                    {
                        _CurrentFrame = 0;
                    }
                    else
                    {
                        _TimeLine[++_CurrentFrame] = Frame.CreateFrame();
                    }
                    break;
                }
                case TagType.PlaceObject:
                case TagType.PlaceObject2:
                case TagType.PlaceObject3:
                    _TimeLine[_CurrentFrame].PlaceObjectList.Add(PlaceOperation.CreateFromTag(tag));
                    break;
                case TagType.RemoveObject:
                case TagType.RemoveObject2:
                    _TimeLine[_CurrentFrame].RemoveObjectList.Add(RemoveOperation.CreateFromTag(tag));
                    break;
                case TagType.End:
                    break;
                case TagType.SoundStreamHead:
                case TagType.SoundStreamHead2:
                    break;
                case TagType.StartSound:
                    break;
                case TagType.UnsupportedDefinition:
                    break;
            }
        }
        //----------------------------------------------------------------------
        private void _ParsePlaceTag(IPlaceObject tag)
        {
            switch (tag.TagType)
            {
                case TagType.PlaceObject:
                case TagType.PlaceObject2:
                case TagType.PlaceObject3:
                {
                    break;
                }
            }
        }
    }
}
